<?php
class Session {
    private $sid;
    private $db;
    private $session_data = array();
    function __construct() {
        $this -> db = Reg::get( 'database' );
        if( !isset( $_COOKIE[ Config::get( 'session_cookie_name', 'config' ) ] ) ) {
            $this -> _createSession();
        }else {
            $this -> sid = $_COOKIE[ Config::get( 'session_cookie_name', 'config' ) ];
            $this -> _checkSession();
        }
    }
    
    function __destruct() {
        $stmt = $this -> db -> prepare( 'UPDATE ' . Config::get( 'prefix', 'db_config' ) . 'sessions SET session_last_updated=:time, session_data=:data WHERE session_id=:sid LIMIT 1' );
        $stmt -> bindValue( ':time', time(), PDO::PARAM_INT );
        $stmt -> bindValue( ':data', serialize( $this -> session_data ), PDO::PARAM_STR );
        $stmt -> bindValue( ':sid', $this -> sid, PDO::PARAM_STR );
        $stmt -> execute();
    }
    
    function set( $key, $value ) {
        $this -> session_data[ $key ] = $value;
    }
    
    function get( $key ) {
        return isset( $this -> session_data[ $key ] ) ? $this -> session_data[ $key ] : false;
    }
    
    private function _createSession() {
        $this -> sid = uniqid( 'sid', true );
        if( isset( $_SERVER["REMOTE_ADDR"] ) ) {
            $ip = $_SERVER["REMOTE_ADDR"];
        }else if( isset( $_SERVER["HTTP_X_FORWARDED_FOR"] ) ) {
            $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
        }else if( isset( $_SERVER["HTTP_CLIENT_IP"] ) ) {
            $ip = $_SERVER["HTTP_CLIENT_IP"];
        } 
        $stmt = $this -> db -> prepare( 'INSERT INTO ' . Config::get( 'prefix', 'db_config' ) . 'sessions SET session_id=:sid, session_last_updated=:last_update, user_agent=:user_agent, user_ip=:user_ip' );
        $stmt -> bindValue( ':sid', $this -> sid, PDO::PARAM_STR );
        $stmt -> bindValue( ':last_update', time(), PDO::PARAM_STR );
        $stmt -> bindValue( ':user_agent', $_SERVER[ 'HTTP_USER_AGENT' ], PDO::PARAM_STR );
        $stmt -> bindValue( ':user_ip', $ip, PDO::PARAM_STR );
        $stmt -> execute();
        setcookie( Config::get( 'session_cookie_name', 'config' ), $this -> sid, time() + Config::get( 'session_lifetime', 'config' ), URLPATH );
    }
    private function _checkSession() {
        $stmt = $this -> db -> prepare( 'SELECT * FROM ' . Config::get( 'prefix', 'db_config' ) . 'sessions WHERE session_id=:sid LIMIT 1' );
        $stmt -> bindValue( ':sid', $this -> sid, PDO::PARAM_STR );
        $stmt -> execute();
        if( $stmt -> rowCount() == 1 ) {
            $session = $stmt -> fetch(PDO::FETCH_OBJ);
            $stmt -> closeCursor();
            if( $session -> session_last_updated + Config::get( 'session_lifetime', 'config' ) < time() || $session -> user_agent != $_SERVER['HTTP_USER_AGENT'] ) {
                $this -> destroy();
            }else {
                $this -> session_data = (array)unserialize( $session -> session_data );
            }
        }else
            $this -> destroy();
    }
    private function destroy() {
        setcookie( Config::get( 'session_cookie_name', 'config' ), null, 0, URLPATH );
        $stmt = $this -> db -> prepare( 'DELETE FROM ' . Config::get( 'prefix', 'db_config' ) . 'sessions WHERE session_id=:sid OR session_last_updated < :time' );
        $stmt -> bindValue( ':sid', $this -> sid, PDO::PARAM_STR );
        $stmt -> bindValue( ':time', (time() - Config::get( 'session_lifetime', 'config' )), PDO::PARAM_INT );
        $stmt -> execute();
    }
}